#include "FLOAT.h"
#include <stdint.h>

typedef union {
	struct {
		uint32_t m : 23; //m: 存储尾数部分
		uint32_t e : 8; //e: 存储指数部分
		uint32_t s : 1; //符号位
	};
	uint32_t val; //val: 存储浮点数 a 的原始 32 位表示
} Float;

#define __sign(x) ((x) & 0x80000000)
#define __scale(x) (__sign(x) ? -(x) : (x))

FLOAT F_mul_F(FLOAT a, FLOAT b) {
	int64_t scale = ((int64_t)a * (int64_t)b) >> 16;
	return scale;
}

FLOAT F_div_F(FLOAT a, FLOAT b) {
	/* Dividing two 64-bit integers needs the support of another library
	 * `libgcc', other than newlib. It is a dirty work to port `libgcc'
	 * to NEMU. In fact, it is unnecessary to perform a "64/64" division
	 * here. A "64/32" division is enough.
	 *
	 * To perform a "64/32" division, you can use the x86 instruction
	 * `div' or `idiv' by inline assembly. We provide a template for you
	 * to prevent you from uncessary details.
	 *
	 *     asm volatile ("??? %2" : "=a"(???), "=d"(???) : "r"(???), "a"(???), "d"(???));
	 *
	 * If you want to use the template above, you should fill the "???"
	 * correctly. For more information, please read the i386 manual for
	 * division instructions, and search the Internet about "inline assembly".
	 * It is OK not to use the template above, but you should figure
	 * out another way to perform the division.
	 */

    FLOAT q, r;
	asm volatile("idiv %2" : "=a"(q), "=d"(r) : "r"(b), "a"(a << 16), "d"(a >> 16));
	//asm volatile ("指令 %操作数" : 输出操作数列表 : 输入操作数列表 : 易变寄存器列表);
	// "=a" 和 "=d" 分别表示将结果存储在 EAX 和 EDX 寄存器中。
	// "r" 表示将变量存储到任意的通用寄存器中，"a" 和 "d" 分别表示 EAX 和 EDX 寄存器。
	//asm 用于定义内联汇编,volatile 关键字表示编译器不能优化或删除这个汇编代码块，因为它可能有副作用
	// "idiv %2"：idiv 是带符号除法指令，除数在 %2。
	// =a(quotient)：商存储在 EAX，即输出变量 quotient。
	// =d(remainder)：余数存储在 EDX，即输出变量 remainder。
	// r(divisor)：divisor 是输入变量，存储在任意一个通用寄存器中。
	// a(low)：被除数的低 32 位存储在 EAX。
	// d(high)：被除数的高 32 位存储在 EDX。
	return q;
}

FLOAT f2F(float a) {
	/* You should figure out how to convert `a' into FLOAT without
	 * introducing x87 floating point instructions. Else you can
	 * not run this code in NEMU before implementing x87 floating
	 * point instructions, which is contrary to our expectation.
	 *
	 * Hint: The bit representation of `a' is already on the
	 * stack. How do you retrieve it to another variable without
	 * performing arithmetic operations on it directly?
	 */

	Float f;
	void *temp = &a;
	//这里使用 void* 类型的指针来避免类型检查，将 float 类型的 a 转换为 uint32_t 类型的位表示。
	f.val = *(uint32_t *)temp;
	//f.val 保存了 a 的 32 位浮点数表示（IEEE 754 格式）
	uint32_t m = f.m | (1 << 23);
	//这是对 m（尾数）进行操作的部分。IEEE 754 规范中，浮点数的尾数是隐含的，这里将其补上第 24 位的隐含 1
	int shift = 134 - (int)f.e;//134 是为了抵消偏移量，计算得到的 shift 用于调整尾数的实际位置
//	assert(shift <= 23 && shift >= -7);
	if(shift < 0) {
		m <<= (-shift);
	}
	else {
		m >>= shift;
	}
	//如果 shift 小于 0，表示指数较大，需要将尾数向左移动。
	//如果 shift 大于等于 0，表示指数较小或适中，需要将尾数向右移动。
	return (__sign(f.val) ? -m : m);//判断符号位
}

FLOAT Fabs(FLOAT a) {
	return __scale(a);
}

/* Functions below are already implemented */

FLOAT sqrt(FLOAT x) {
	FLOAT dt, t = int2F(2);

	do {
		dt = F_div_int((F_div_F(x, t) - t), 2);
		t += dt;
	} while(Fabs(dt) > f2F(1e-4));

	return t;
}

FLOAT pow(FLOAT x, FLOAT y) {
	/* we only compute x^0.333 */
	FLOAT t2, dt, t = int2F(2);

	do {
		t2 = F_mul_F(t, t);
		dt = (F_div_F(x, t2) - t) / 3;
		t += dt;
	} while(Fabs(dt) > f2F(1e-4));

	return t;
}

